"""Music routes."""
from flask import request, current_app
from flask_restx import Namespace, Resource, fields
from flask_jwt_extended import jwt_required, get_jwt_identity
from app.models.poi import POI
from app.models.walking_session import WalkingSession
from app.models.music import Music
from app.services.music_service import MusicService
from app.routes.mock_data import MOCK_MUSIC_LIBRARY

# Import Celery task - may not be available in all environments
try:
    from app.tasks.music_tasks import generate_and_save_music
    CELERY_AVAILABLE = True
except ImportError:
    CELERY_AVAILABLE = False

api = Namespace('music', description='Music operations')

# Models
generate_music_model = api.model('GenerateMusic', {
    'poi_id': fields.String(required=True),
    'session_id': fields.String(required=True),
    'mood': fields.String(description='Mood/atmosphere', default='relaxing')
})

save_music_model = api.model('SaveMusic', {
    'file_url': fields.String(required=True, description='URL to music file'),
    'duration': fields.Integer(required=True, description='Duration in seconds'),
    'session_id': fields.String(description='Session ID'),
    'poi_id': fields.String(description='POI ID'),
    'metadata': fields.Raw(description='Additional metadata')
})


@api.route('/library')
class MusicLibrary(Resource):
    """Music library endpoint."""
    
    def get(self):
        """Get user's music library.
        
        Validates: Requirements 3.4
        """
        # Get pagination parameters
        limit = request.args.get('limit', type=int)
        offset = request.args.get('offset', type=int, default=0)
        
        try:
            # Try to get from database
            music_service = MusicService()
            music_list = music_service.get_user_music_library('dev_user', limit, offset)
            music_data = [music.to_dict() for music in music_list]
            
            if music_data:
                return {
                    'music': music_data,
                    'count': len(music_data)
                }, 200
        except Exception:
            pass
        
        # Return mock music library as fallback
        return {
            'music': MOCK_MUSIC_LIBRARY,
            'count': len(MOCK_MUSIC_LIBRARY),
            'is_mock': True
        }, 200


@api.route('/generate')
class GenerateMusic(Resource):
    """Generate music endpoint."""
    
    @jwt_required()
    @api.expect(generate_music_model)
    def post(self):
        """Generate background music asynchronously.
        
        Validates: Requirements 3.2
        """
        user_id = get_jwt_identity()
        data = request.get_json()
        
        # Get parameters
        poi_id = data.get('poi_id')
        session_id = data.get('session_id')
        mood = data.get('mood', 'relaxing')
        
        if not poi_id or not session_id:
            api.abort(400, 'poi_id and session_id are required')
        
        # Verify POI exists
        poi = POI.query.get(poi_id)
        if not poi:
            api.abort(404, 'POI not found')
        
        # Verify session exists and belongs to user
        session = WalkingSession.query.get(session_id)
        if not session:
            api.abort(404, 'Session not found')
        
        if session.user_id != user_id:
            api.abort(403, 'Unauthorized to generate music for this session')
        
        if not CELERY_AVAILABLE:
            api.abort(503, 'Music generation service is not available')
        
        try:
            # Get weather data for context
            from app.services.weather_service import WeatherService
            from app.models.location import Location
            
            qweather_key = current_app.config.get('QWEATHER_KEY')
            redis_url = current_app.config.get('REDIS_URL')
            cache_duration = current_app.config.get('WEATHER_CACHE_DURATION_SECONDS', 1800)
            
            weather_data = {}
            if session.current_latitude and session.current_longitude:
                try:
                    location = Location(
                        latitude=session.current_latitude,
                        longitude=session.current_longitude,
                        accuracy=10.0
                    )
                    weather_service = WeatherService(qweather_key, redis_url, cache_duration)
                    weather = weather_service.get_current_weather(location)
                    weather_data = {
                        'temperature': weather.temperature,
                        'condition': weather.condition,
                        'humidity': weather.humidity,
                        'wind_speed': weather.wind_speed,
                        'aqi': weather.aqi,
                        'timestamp': weather.timestamp.isoformat()
                    }
                except Exception:
                    # Weather is optional
                    pass
            
            # Trigger async music generation task
            task = generate_and_save_music.delay(
                user_id,
                session_id,
                poi.to_dict(),
                weather_data,
                mood
            )
            
            return {
                'message': 'Music generation started',
                'task_id': task.id,
                'status': 'pending'
            }, 202
            
        except Exception as e:
            api.abort(500, f'Failed to start music generation: {str(e)}')


@api.route('/<string:music_id>/save')
class SaveMusic(Resource):
    """Save music endpoint."""
    
    @jwt_required()
    def post(self, music_id):
        """Mark music as saved in library (if it was temporary).
        
        Validates: Requirements 3.4
        """
        user_id = get_jwt_identity()
        
        # Get music
        music = Music.query.get(music_id)
        if not music:
            api.abort(404, 'Music not found')
        
        if music.user_id != user_id:
            api.abort(403, 'Unauthorized to save this music')
        
        # Music is already saved in the database
        # This endpoint can be used to add additional metadata or mark as favorite
        data = request.get_json() or {}
        
        # Initialize music service
        music_service = MusicService()
        
        try:
            # Update metadata if provided
            if 'metadata' in data:
                metadata = data['metadata']
                metadata['saved_at'] = music_service._get_current_timestamp()
                music_service.update_music_metadata(music_id, user_id, metadata)
            
            return {
                'message': 'Music saved successfully',
                'music': music.to_dict()
            }, 200
            
        except Exception as e:
            api.abort(500, f'Failed to save music: {str(e)}')


@api.route('/save')
class SaveNewMusic(Resource):
    """Save new music endpoint."""
    
    @jwt_required()
    @api.expect(save_music_model)
    def post(self):
        """Save new music to library.
        
        Validates: Requirements 3.4
        """
        user_id = get_jwt_identity()
        data = request.get_json()
        
        # Get parameters
        file_url = data.get('file_url')
        duration = data.get('duration')
        session_id = data.get('session_id')
        poi_id = data.get('poi_id')
        metadata = data.get('metadata', {})
        
        if not file_url or duration is None:
            api.abort(400, 'file_url and duration are required')
        
        # Initialize music service
        music_service = MusicService()
        
        try:
            # Save music
            music = music_service.save_music(
                user_id=user_id,
                file_url=file_url,
                duration=duration,
                session_id=session_id,
                poi_id=poi_id,
                metadata=metadata
            )
            
            return {
                'message': 'Music saved successfully',
                'music': music.to_dict()
            }, 201
            
        except ValueError as e:
            api.abort(400, str(e))
        except Exception as e:
            api.abort(500, f'Failed to save music: {str(e)}')


@api.route('/<string:music_id>')
class MusicDetail(Resource):
    """Music detail endpoint."""
    
    @jwt_required()
    def delete(self, music_id):
        """Delete music from library.
        
        Validates: Requirements 3.4
        """
        user_id = get_jwt_identity()
        
        # Get music
        music = Music.query.get(music_id)
        if not music:
            api.abort(404, 'Music not found')
        
        if music.user_id != user_id:
            api.abort(403, 'Unauthorized to delete this music')
        
        # Initialize music service
        music_service = MusicService()
        
        try:
            # Delete music
            music_service.delete_music(music_id, user_id)
            
            return {
                'message': 'Music deleted successfully'
            }, 200
            
        except ValueError as e:
            api.abort(400, str(e))
        except Exception as e:
            api.abort(500, f'Failed to delete music: {str(e)}')
